/***************************************************************************** 
** common/oem_func.c
** 
** Copyright (c) 2009~2014 ShangHai Infotm Ltd all rights reserved. 
** 
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** Description: OEM functions.
**
** Author:
**     Warits   <warits.wang@infotm.com>
**      
** Revision History: 
** ----------------- 
** 1.1  XXX 02/01/2010 XXX	Warits
** 1.2  xxx 09/12/2011 xxx  John     Modified to make it more clear
*****************************************************************************/

#include <common.h>
#include <command.h>
#include <oem_func.h>
#include <oem_font.h>
#include <oem_graphic.h>
#include <oem_pic.h>
#include <asm/io.h>
#include <nand.h>

int oem_mmc_init(int channel)
{
	int ret;

	char *arg_rescan[] = {"mmc", "rescan", "0"};
#ifdef SOURCE_CHANNEL
	sprintf(arg_rescan[2], "%d", channel);
#endif
	ret = do_mmcops(NULL, 0, 3, arg_rescan);
	return ret;
}
/*
static char * __scr_p;

static int oem_valid_bootscr(uint32_t addr)
{
	uint8_t header[] = {
		0x0a, 0x2d, 0x2d, 0x5b, 0x5b, 0x75, 0x62, 0x6f,
		0x6f, 0x74, 0x2e, 0x73, 0x63, 0x72, 0x69, 0x70,
		0x74, 0x0a,};
	uint8_t *p = (uint8_t *)addr;

	int i;
	for(i = 0; i < ARRAY_SIZE(header); i++)
	  if(*p++ ^ header[i])
		return 0;

	__scr_p = (char *)p;
	for(i = 0; i < 0x1000; i++, p++)
	  if(*p == 0xa
		 && *(p + 1) == 0x5d
		 && *(p + 2) == 0x5d)
		return 1;		// Valid Script 
	return 0;
}*/
/*
static int __get_sd_script(char *str)
{
	while((*__scr_p == 0x0a)
	   || (*__scr_p == 0x2d)
	   || (*__scr_p == 0x5b)) __scr_p++;

	if(*(uint16_t *)__scr_p == 0x5d5d)
	{
		*str = 0;
		return 0;
	}

	while((*__scr_p != 0x0a)
	   && (*__scr_p != 0x5d)) *str++ = *__scr_p++;
	*str = '\0';

	return 1;
}
*/
int load_file_sd(char *filename,unsigned int addr )
{
	char cmd[64];

	sprintf(cmd,"fatload mmc %d:1 %x %s",SOURCE_CHANNEL,addr,filename);
	if(!run_command(cmd,0)){
		return 0;
	}
	return 1;
}
/*
static int oem_check_bootsd(uint32_t basemem){
	char cmd[64];
	char script[2][64] = {"/android/bootscr.bin", "/infofirmware/scr/bootscr.bin"};
	sprintf(cmd, "mmc read %d %x 400 8", SOURCE_CHANNEL , basemem);
	run_command(cmd, 0);
	if(oem_valid_bootscr(basemem))
		return 0;
	else {
		load_file_sd(script[0],basemem);
		if(oem_valid_bootscr(basemem))
		{
			return 0;
		} else {
			load_file_sd(script[1],basemem);
			if(oem_valid_bootscr(basemem))
				return 0;
			return -1;
		}
	}
}
*/
extern int oem_burn_img(enum inandimage type, uint8_t *data);
int oem_boot_sd(void)
{
	char cmd[64];
	//char title[256];
/* Try to load script from SD */
	if(oem_mmc_init(SOURCE_CHANNEL)){
		printf("No card in the source channel\n");
		return 1;
	}	
	printf("Try booting from SD ...\n");
//	oem_simpro_finish(" Try booting from SD ...");
	/* Load data from sd */
	
	unsigned char get_image=0;
/*
#ifndef CONFIG_TEST_VERSION
	sprintf(cmd,"fatload mmc %d:1 47c00000 pcb_test.bin",SOURCE_CHANNEL);
	if(!run_command(cmd,0)){
		//oem_simpro_finish("Starting PCB test program...");
		run_command("go 47c00000",0);
	}
#endif
*/
	/*****************try update u-boot*****************/
	//char uboot=0;
	sprintf(cmd,"fatload mmc %d:1 40008000 android/u-boot-nand.bin",SOURCE_CHANNEL);
	if(!run_command(cmd,0)){
		//uboot=1;
		//get_image=1;
		//run_command("adr u0 40008000 ",0);
		//oem_clear_screen(0);
		get_image = 1;
		oem_burn_U0((uint8_t *)0x40008000);
	}

	/*************prepare for image update**************/
/*
#ifdef CONFIG_SYS_DISK_MMC
	if(oem_mmc_init(SYS_DISK_CHANNEL)){
		printf("Can not initiate system card for image burn\n");
		return 1;
	}
#endif
*/
#if 0 
	memset((uint8_t *)CONFIG_RESV_SCRIPT, 0, 4096);
	if(oem_check_bootsd((uint32_t)CONFIG_RESV_SCRIPT)){
		printf("Invalid boot SD!\n");
	}else{	
		 sprintf(cmd, "mmc read %d %x 400 8", SOURCE_CHANNEL , CONFIG_RESV_SCRIPT);
		  run_command(cmd, 0);
		/* Run SD scripts */
		while(__get_sd_script(cmd))
		{
			if(strstr(cmd, "iuw"))
			{
				printf("IUW found in command list. The commands will be executed.\n");
				sprintf(cmd, "mmc read %d 40008000 800 30000", SOURCE_CHANNEL);
				run_command(cmd, 0);
				run_command("iuw 40008000", 0);

				//oem_simpro_finish("IUW command list finished, you should not see this image.");
				/* This should never be reached */
				return 0;

			}
		}
		get_image=1;
	}
#endif

	if(!load_file_sd("android/uImage",  CONFIG_SYS_PHY_LK_BASE ) ) 
	{
		printf("Burning uImage\n");
		oem_burn_LK((uint8_t *)CONFIG_SYS_PHY_LK_BASE);
		get_image = 1;
	} 
		
	if(!load_file_sd("android/system.img",  CONFIG_SYS_PHY_LK_BASE ) ) 
	{
		printf("Burning system.img\n");
		oem_burn_SYS((uint8_t *)CONFIG_SYS_PHY_LK_BASE);
		get_image = 1;
		//oem_set_boot_type(BOOT_FACTORY_INIT);
	} 

	if(!load_file_sd("android/config.img",  CONFIG_SYS_PHY_LK_BASE ) ) 
	{
		printf("Burning config.img, which is a dummy jffs2 image\n");
		oem_burn_img(CONFIG, (uint8_t *)CONFIG_SYS_PHY_LK_BASE);
		get_image = 1;
		//oem_set_boot_type(BOOT_FACTORY_INIT);
	} 
	if(!load_file_sd("android/camera_id",  CONFIG_SYS_PHY_LK_BASE ) ) 
	{
		printf("Burning camera_id\n");
		oem_burn_ID((uint8_t *)CONFIG_SYS_PHY_LK_BASE);
		get_image = 1;
		//oem_set_boot_type(BOOT_FACTORY_INIT);
	} 
	

#if 0 
	char imagest[2]={0,0};
	char file[2][32]={	
		"system.img",
		"uImage"
	};

	unsigned int rambase[6]={
		CONFIG_SYS_PHY_LK_BASE,
		CONFIG_SYS_PHY_LK_BASE
	};

	int (*imageburn[6])(uint8_t * data )={	
		oem_burn_SYS,
		oem_burn_LK
	};

	int i=0;
	printf("here we load image from gaven directory.\n");
	for( i = 0 ;i < 6; i++){
		char filename[32];
		sprintf(filename,"android/%s",file[i]);

		if(!load_file_sd(filename,rambase[i] )){	
			imagest[i]= (imageburn[i]((uint8_t *)rambase[i]))? 0x01: 0x11;
			get_image=1;
		}
	}

	/*
	if(0x11!=imagest[0]){//if no system.img in the source disk, try load and burn zSYS.img
		if(!load_file_sd("android/zSYS.img",(unsigned int)CONFIG_SYS_PHY_LK_BASE)){
			if(!oem_burn_zSYS((uint8_t *)CONFIG_SYS_PHY_LK_BASE)){
				imagest[2]=0x11;
			}
			get_image=1;
		}
	}
	*/

	if(0x11==imagest[1]){
		oem_set_boot_type(BOOT_FACTORY_INIT);
		return 0;
	}
#endif
	/*
	 * TODO 
	 */
//	if(get_image==1)	
//	{
	//	sprintf(title, "%s %s %s %s updated OK,please take off SD and reboot",
	//			(uboot ? "U0":""),((imagest[1]==0x11) ? "uImage":""),((imagest[4]==0x11) ? "bootlogo":""),((imagest[5]==0x11) ? "kernlogo":""));
		//oem_simpro_finish(title);
//	}
#if 0

	if(0x11==imagest[1]){
		printf("Image update finished.\n\r");
		oem_simpro_finish("Image updated OK, please take off SD and reboot.");
	}else if(uboot){
		printf("U-boot update finished.\n\r");
		oem_simpro_finish("U0 updated OK, please take off SD and reboot.");
	}else{
		printf("No valid image found in directory android/. \
				To bur system corecttly system.img, uImage, ramdisk.img, recovery-rd.img are needed\n");
	}
#endif
#ifndef CONFIG_TEST_VERSION
	if(get_image==1){
		for(;;){
			if(oem_mmc_init(SOURCE_CHANNEL))
				reset_cpu(0);
			udelay(500000);
		}
	}
#endif
	return 0;//never reached here
}

void oem_consume_keypress(void)
{
	int i;
	for(i = 0; i < 100; i++)
	{
		if(tstc())
			getc();
	}
}

uint8_t oem_getc(void)
{
	oem_consume_keypress();
	return getc();
}

void oem_getc_exec_gpio(uint32_t gpio, int num)
{
	while(!(readl(gpio) & (1 << num)));
	while((readl(gpio) & (1 << num)));
	while(!(readl(gpio) & (1 << num)));

	return ;
}

void oem_getc_exec(uint8_t a)
{
	while(1)
		if(oem_getc() == a)
			break;
}

int oem_tstc_gpio(uint32_t gpx, uint32_t bit)
{
	return !!(readl(gpx) & (1 << bit));
}
#if 0 
static int oem_read_misc_recovery_flag(void)
{
	int length=0;
	uint8_t * buffer=NULL;
	int boottype=BOOT_NORMAL;

	length= (CONFIG_BOOT_INFO_LEN + 0xfff) & (~0xfff);
	buffer=(uint8_t *)malloc((size_t)length);

	if(!buffer){
		return boottype;
	}
	if(!oem_read_sys_disk(buffer, CONFIG_SYS_DISK_MISC_OFFS ,length)){
		char *s=((struct boottype_info *)buffer)->command;
		if(!strncmp("boot-recovery",s,13)) 
			boottype=BOOT_ONLINE_UPDATE;
	}

	if(buffer) free((void*)buffer);
	return boottype;
}
#endif 
int oem_set_boot_type(int type)
{
	char env[16];
	sprintf(env,"%d",type);
	setenv("boottype",env);
	return type;
}

int oem_got_boot_info(void)
{
	char* s=getenv("boottype");
	if(s)return 1;//boot type has been set. 
#ifdef CONFIG_RECOVERY_KEY1_GPIO
	u32 tmp0;
	tmp0 = readl(CONFIG_RECOVERY_KEY1_GPIO+4);
	tmp0 = tmp0 & (~(3 << CONFIG_RECOVERY_KEY1_GPIO_NUM*2));
	writel(tmp0,CONFIG_RECOVERY_KEY1_GPIO+4);
	if(!(readl(CONFIG_RECOVERY_KEY1_GPIO) & (1 << CONFIG_RECOVERY_KEY1_GPIO_NUM)))
		return oem_set_boot_type(BOOT_ONLINE_UPDATE);
#endif
	int type=BOOT_NORMAL;
#if 0
	type=oem_read_misc_recovery_flag();
#endif 
	if(BOOT_NORMAL!=type)return oem_set_boot_type(type);   

	if(readl(RST_ST) & 0x8){                            
		if(readl(INFO3) == CONFIG_PRODUCT_LINUX_RVFLAG) 
		{                                                 
			/* Clear RVFLAG */                            
			writel(0, INFO3);                             
			return oem_set_boot_type(BOOT_ONLINE_UPDATE );                 
		}else{
			if(readl(INFO3)==CONFIG_PRODUCT_LINUX_RV3FLAG){
				writel(0, INFO3);
				return oem_set_boot_type(BOOT_FACTORY_RESET);      
			}
		}
	}         
	return oem_set_boot_type(BOOT_NORMAL);
}
int oem_got_boot_type(void)
{
	char* s=getenv("boottype");
	return s? simple_strtoul (s, NULL, 10) : 0;
}

void oem_print_eye(char *s)
{
	char str[32];
	sprintf(str, "E%02X%02X%02X%02X%02X%02X%02X%02X\n",
			(readl(DENALI_CTL_PA_62) >> 8) & 0x7f,
			(readl(DENALI_CTL_PA_63) >> 8) & 0x7f,
			(readl(DENALI_CTL_PA_64) >> 8) & 0x7f,
			(readl(DENALI_CTL_PA_65) >> 8) & 0x7f,
			(readl(DENALI_CTL_PA_66) >> 8) & 0x7f,
			(readl(DENALI_CTL_PA_67) >> 8) & 0x7f,
			(readl(DENALI_CTL_PA_68) >> 8) & 0x7f,
			(readl(DENALI_CTL_PA_69) >> 8) & 0x7f);

	printf("%s", str);
	if(s)
	{
		memset(s, 0, 32);
		memcpy(s, str, 17);
	}

	return ;
}

#ifdef CONFIG_RESET_CHECK
#define CONFIG_IMAPX200_FRIST_RESET     (0x66626f74)
#define CONFIG_IMAPX200_SECOND_RESET    (0x73626f74)
#define CONFIG_IMAPX200_REQ_REASE       (0x72656173)


void oem_check_reset(void)
{

	uint32_t resetState = 0;
	uint8_t menukey, homekey;

	resetState = readl(INFO1);


	if(resetState == CONFIG_IMAPX200_REQ_REASE)
	{
		//oem_clear_screen(0);
	        //oem_mid("X ERROR OCCURRED: BOOTING SYSTEM FAILURE X");
		//oem_mid2("You can select YES to try recover, but your personal data will be lost.");
		//oem_below("HOME=YES  MENU=NO");        	


		do
		{
			menukey = oem_tstc_gpio(CONFIG_MENU_KEY_GPIO, CONFIG_MENU_KEY_GPIO_NUM);
			homekey = oem_tstc_gpio(CONFIG_RECOVERY_KEY1_GPIO, CONFIG_RECOVERY_KEY1_GPIO_NUM);
		}
		while(menukey && homekey);

		printf("homekey = %x, menukey = %x\n", homekey, menukey);
		if(homekey == 0)
		{
			oem_set_boot_args(BOOT_FACTORY_RESET);
		}


		writel(0x0, INFO1);
	}
}
#endif//CONFIG_RESET_CHECK

void oem_set_boot_args(int boottype)
{
	char boot_arg[512];
	char camera_id[ID_LEAN];
	oem_load_camera_id(camera_id);
	camera_id[ID_LEAN-1] = 0;
#ifndef CONFIG_NFS_BOOTARGS
	sprintf(boot_arg, "%s",  CONFIG_LINUX_DEFAULT_BOOTARGS);
#else 
	sprintf(boot_arg, "%s",  CONFIG_LINUX_NFS_BOOTARGS);
#endif

	if(strncmp(camera_id,"ipcam_udid",10) == 0)
	{
		strcat(boot_arg, " " );
		strcat(boot_arg, camera_id);
	}
	
	setenv("bootargs", boot_arg);
}

